package com.kun.companion.core.thread;

import com.kun.companion.core.context.annotation.Component;
import com.kun.companion.core.exception.BizException;
import com.kun.companion.core.util.ComUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Comparator;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;

/**
 * TODO
 *
 * @author gzc
 * @since 2025/2/7 10:26
 **/
@Component
public class ComThreadPool extends AbstractThreadPool {
    private static final Logger log = LoggerFactory.getLogger(ComThreadPool.class);
    /**
     * 线程名称前缀
     */
    private static final String POOL_THREAD_PREFIX = "pool";
    /**
     * 1+目标IO耗时/目标CPU耗时
     */
    private static final int FACTOR = 1 + 500 / 20;
    /**
     * 核心数
     */
    private static final int CPU_CORE = Runtime.getRuntime().availableProcessors();
    /**
     * 线程池核心数大小
     */
    private static final int POOL_CORE_SIZE = CPU_CORE * FACTOR;
    /**
     * 线程池线程最大数量
     */
    private static final int POOL_MAX_SIZE = POOL_CORE_SIZE * 2;
    /**
     * 存活时间 30秒
     */
    private static final long KEEP_ALIVE_TIME = 30_000L;
    /**
     * 存活时间类型(毫秒)
     */
    private static final TimeUnit KEEP_ALIVE_TIME_TIME_UNIT = TimeUnit.MILLISECONDS;
    /**
     * 容纳能力
     */
    private static final int CAPACITY = 1000;

    public ComThreadPool() {
        super();
    }

    @Override
    protected ThreadPoolExecutor createPool() {
        // 定义一个 Comparator 来比较任务的优先级，优先级数值越大越优先
        Comparator<Runnable> comparator = (r1, r2) -> {
            if (r1 instanceof PrioritizedTask && r2 instanceof PrioritizedTask) {
                return Integer.compare(((PrioritizedTask) r1).getPriority(), ((PrioritizedTask) r2).getPriority());
            }
            if (r1 instanceof PriorityFutureTask && r2 instanceof PriorityFutureTask) {
                return Integer.compare(((PriorityFutureTask) r1).getPrioritizedTask().getPriority(),
                        ((PriorityFutureTask) r2).getPrioritizedTask().getPriority());
            }
            String warnMsg = """
                    线程池任务优先级排序错误，任务对象r1 -> {}  r2 -> {}，造成此问题的原因有可能是:
                    1.任务未封装成PriorityFutureTask或PrioritizedTask对象。
                    2.线程池任务超过最大线程数则会将任务交由调用线程来执行。
                    """;
            log.warn(warnMsg, r1, r2);
            return -1;
        };
        // 创建线程池
        return new PriorityThreadPoolExecutor(
                POOL_CORE_SIZE,
                POOL_MAX_SIZE,
                KEEP_ALIVE_TIME,
                KEEP_ALIVE_TIME_TIME_UNIT,
                new PriorityBlockingQueue<>(CAPACITY, comparator),
                new NamedThreadFactory(POOL_THREAD_PREFIX),
                // 当线程池无法接受新任务时，将任务交由调用线程（即提交任务的线程）来执行
                new ThreadPoolExecutor.CallerRunsPolicy());
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        FutureTask<T> futureTask = new FutureTask<>(task);
        execute(futureTask);
        return futureTask;
    }

    @Override
    public Future<?> submit(Runnable task) {
        if (task instanceof PrioritizedTask) {
            return pool.submit(task);
        } else {
            return pool.submit(new PrioritizedTask(task));
        }
    }

    @Override
    public Future<?> submitUI(Runnable task) {
        Runnable runnable = () -> ComUtil.uiThreadRun(task);
        if (task instanceof PrioritizedTask) {
            return pool.submit(runnable);
        } else {
            return pool.submit(new PrioritizedTask(runnable));
        }
    }

    @Override
    public void execute(Runnable task) {
        if (task instanceof PrioritizedTask) {
            pool.execute(task);
        } else {
            pool.execute(new PrioritizedTask(task));
        }
    }

    @Override
    public void executeUI(Runnable task) {
        Runnable runnable = () -> ComUtil.uiThreadRun(task);
        if (task instanceof PrioritizedTask) {
            pool.execute(runnable);
        } else {
            pool.execute(new PrioritizedTask(runnable));
        }
    }

    @Override
    public CompletableFuture<Void> runAsync(Runnable runnable) {
        return CompletableFuture.runAsync(runnable, this::execute);
    }

    @Override
    public CompletableFuture<Void> runAsyncUI(Runnable runnable) {
        return CompletableFuture.runAsync(() -> ComUtil.uiThreadRun(runnable), this::execute);
    }

    public CompletableFuture<Void> runAsync(PrioritizedTask prioritizedTask) {
        return CompletableFuture.runAsync(prioritizedTask, pool);
    }

    @Override
    public <T> CompletableFuture<T> supplyAsyncCallable(Callable<T> callable) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return callable.call();
            } catch (Exception e) {
                throw new CompletionException(e);
            }
        }, this::execute);
    }

    @Override
    public <T> CompletableFuture<T> supplyAsync(Supplier<T> supplier) {
        return CompletableFuture.supplyAsync(supplier, this::execute);
    }

    @Override
    public <T> CompletableFuture<T> supplyAsyncUI(Supplier<T> supplier) {
        return supplyAsync(() -> {
            AtomicReference<T> result = new AtomicReference<>();
            ComUtil.uiThreadRun(() -> {
                try {
                    result.set(supplier.get());
                } catch (Exception e) {
                    throw new BizException("JS执行失败", e);
                }
            });
            return result.get();
        });
    }


    public <T> CompletableFuture<T> supplyAsync(PriorityFutureTask<T> priorityFutureTask) {
        CompletableFuture<T> future = new CompletableFuture<>();
        execute(() -> {
            try {
                priorityFutureTask.run();
                T result = priorityFutureTask.get();
                future.complete(result);
            } catch (Throwable t) {
                future.completeExceptionally(t);
            }
        });
        return future;
    }

}
